package calc

import (
	"fmt"
	"github.com/thoas/go-funk"
)

type FARule struct {
	state     string
	inputChar string
	nextState string
}

func NewFARule(state string, inputChar string, nextState string) FARule {
	return FARule{
		state,
		inputChar,
		nextState,
	}
}

func (rule FARule) AppliesTo(state string, inputChar string) bool {
	return rule.state == state && rule.inputChar == inputChar
}

func (rule FARule) Follow() string {
	return rule.nextState
}

func (rule FARule) ToString() string {
	return fmt.Sprintf(
		"#<FARule #{%s} -- #{%s} --> #{%s}>", rule.state, rule.inputChar, rule.nextState)
}

type DFARuleBook struct {
	rules []FARule
}

func NewDFARuleBook(rules []FARule) DFARuleBook {
	return DFARuleBook{
		rules: rules,
	}
}

func (book DFARuleBook) nextState(state string, inputChar string) string {
	return book.ruleFor(state, inputChar).nextState
}

// 找到对应的 rule
func (book DFARuleBook) ruleFor(state string, inputChar string) *FARule {
	for _, rule := range book.rules {
		if rule.AppliesTo(state, inputChar) {
			return &rule
		}
	}
	return nil
}

type DFA struct {
	currentStatus string
	acceptStates  []string
	ruleBook      DFARuleBook
}

func NewDFA(currentState string, acceptStates []string, ruleBook DFARuleBook) DFA {
	return DFA{
		currentState,
		acceptStates,
		ruleBook,
	}
}

// 只是判断当前是否是可接受状态
func (dfa DFA) isAccepting() bool {
	return funk.IndexOf(dfa.acceptStates, dfa.currentStatus) != -1
}

func (dfa *DFA) readChar(char string) {
	dfa.currentStatus = dfa.ruleBook.nextState(dfa.currentStatus, char)
}
